package own.stu.jobgib.playown.dp.proxy;

import lombok.extern.slf4j.Slf4j;
import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Date;


@Slf4j
public class DProxy {
    public static void main(String[] args) {

        ClassLoader classLoader = UserService.class.getClassLoader();

        UserServiceImpl userService = new UserServiceImpl();
        UserService proxyInstance = (UserService) Proxy.newProxyInstance(
                classLoader, UserServiceImpl.class.getInterfaces(), create(userService));
        proxyInstance.login("hi", "122");
        proxyInstance.register("hi");
    }

    static InvocationHandler create(final Object delegate) {
        return new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                log.info("invoke method[{}] start on {} ", method.getName(), new Date());
                Object result = method.invoke(delegate, args);
                log.info("invoke method[{}] end on {} ", method.getName(), new Date());
                return result;
            }
        };
    }

    private static void generateProxyClassFile() {

        ClassLoader classLoader = UserService.class.getClassLoader();

        String proxyName = "$Proxy0";
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass("$Proxy0", UserService.class.getInterfaces(), 17);

        Method[] declaredMethods = Proxy.class.getDeclaredMethods();
        for (Method method : declaredMethods) {
            if (!method.getName().equals("defineClass0")) {
                continue;
            }
            System.out.println(method.getName());
            try {
                method.setAccessible(true);
                Class<?> invokeResult = (Class<?>) method.invoke(
                        Proxy.class, classLoader, proxyName, proxyClassFile, 0, proxyClassFile.length);
                System.out.println(invokeResult.getName());
            } catch (Exception e) {
                log.error("invoke error ", e);
            }

//        defineClass0(classLoader, proxyName, proxyClassFile, 0, proxyClassFile.length);
        }

        String path = "Proxy0.class";
        try (FileOutputStream fos = new FileOutputStream(path)) {
            fos.write(proxyClassFile);
            fos.flush();
            System.out.println("代理类class文件写入成功");
        } catch (Exception e) {
            System.out.println("写文件错误");
        }
    }
}
